Introduction

# Load packages we are going to use
pacman::p_load(tidyverse, janitor, plotly, dataMeta, RColorBrewer, gridExtra)
Warning: lzma decoder corrupt datatrying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.1/gridExtra_2.3.tgz'
Content type 'application/x-gzip' length 1102731 bytes (1.1 MB)
==================================================
downloaded 1.1 MB

The downloaded binary packages are in
    /var/folders/jm/zxwjz7rj66qggkx4p6kxg01c0000gn/T//RtmpgJSCIQ/downloaded_packages

gridExtra installed
# Read the data and store it to 'salaries'
salaries <- read.csv(file = '/Users/alvinjiao/Desktop/QTM 302W/Salary.csv')
head(salaries)

Data Exploring

This data, broadly, speaking has information of data science employees and their salaries available on free data-oriented platforms such as Kaggle (note: the author of the original source of the data has just recently switched their profile into private mode, so an alternate link will be used as an substitute: https://www.kaggle.com/code/febiec/data-science-and-tech-salaries-visualization/notebook). To be specific, some of the main variables that are part of this data set include but not limited to: yearly compensation, race, final education level, years of experience, number of years at the current company, and geographic location. This data set was chosen due to the increasingly significant role data literacy and analysis plays in the modern world. Simply put, the importance of data is not only just strictly limited to the academic field but has transformed to be a major integral part that is now fundamentally interlinked with jobs. As the continued relevance of data is growing stronger, the desire for entities - employers - to look skilled personnel can be best seen by their willing to compensate aptly skilled personnel. Granted, even with the same field of expertise, there are factors that contribute disparity. Precisely, to that end, by analyzing this data set, the objective is to depict some relevant and informative insight into some of the factors that might influence a salary of an individual. Thereby gathering a much more holistic view of factors that contribute to the disparity and variations among the personnel within one industry.

The principal aim behind this analysis is to scrutinize as to why total yearly compensation, henceforth referred to as “salary”, differ from the various regions of the United States. In order to achieve this exploration of data, the scope of the data, first and foremost will be limited to include only the values that pertain to the US. Second, although this will be discussed more in-depth in the corresponding section later, the regions that will be used for the duration of this analysis are as follows: Northeast, Midwest, South, and West. Lastly, the central lens that this analysis will be conducted under is via the location in order to scrutinize why there are salary variations among the different regions of one country - the US. To that end, discussions of other variables that might explain the differences in the regionally grouped locations will be conducted especially through exploring the total experience variable in particular.

# Check what classes the variables are in
str(salaries)
'data.frame':   62642 obs. of  29 variables:
 $ timestamp              : chr  "6/7/2017 11:33:27" "6/10/2017 17:11:29" "6/11/2017 14:53:57" "6/17/2017 0:23:14" ...
 $ company                : chr  "Oracle" "eBay" "Amazon" "Apple" ...
 $ level                  : chr  "L3" "SE 2" "L7" "M1" ...
 $ title                  : chr  "Product Manager" "Software Engineer" "Product Manager" "Software Engineering Manager" ...
 $ totalyearlycompensation: int  127000 100000 310000 372000 157000 208000 300000 156000 120000 201000 ...
 $ location               : chr  "Redwood City, CA" "San Francisco, CA" "Seattle, WA" "Sunnyvale, CA" ...
 $ yearsofexperience      : num  1.5 5 8 7 5 8.5 15 4 3 12 ...
 $ yearsatcompany         : num  1.5 3 0 5 3 8.5 11 4 1 6 ...
 $ tag                    : chr  NA NA NA NA ...
 $ basesalary             : num  107000 0 155000 157000 0 0 180000 135000 0 157000 ...
 $ stockgrantvalue        : num  20000 0 0 180000 0 0 65000 8000 0 26000 ...
 $ bonus                  : num  10000 0 0 35000 0 0 55000 13000 0 28000 ...
 $ gender                 : chr  NA NA NA NA ...
 $ otherdetails           : chr  NA NA NA NA ...
 $ cityid                 : int  7392 7419 11527 7472 7322 11527 11521 11527 11521 11527 ...
 $ dmaid                  : int  807 807 819 807 807 819 819 819 819 819 ...
 $ rowNumber              : int  1 2 3 7 9 11 12 13 15 16 ...
 $ Masters_Degree         : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Bachelors_Degree       : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Doctorate_Degree       : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Highschool             : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Some_College           : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Race_Asian             : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Race_White             : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Race_Two_Or_More       : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Race_Black             : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Race_Hispanic          : int  0 0 0 0 0 0 0 0 0 0 ...
 $ Race                   : chr  NA NA NA NA ...
 $ Education              : chr  NA NA NA NA ...
# Check if thear are duplicated observations
get_dupes(salaries) #Check for duplicates: NONE!
No variable names specified - using all columns.

No duplicate combinations found of: timestamp, company, level, title, totalyearlycompensation, location, yearsofexperience, yearsatcompany, tag, ... and 20 other variables

The data set includes 62642 observations and 29 columns to store them. The column variables are illustrated in the data dictionary. Some of which have been already mentioned in the prior section. The data set is partially clean, for its variable types are correct and it does not have any duplicates. However, it is not clean in terms of variable names and missing values. Although this will be addressed once more towards the end of the analysis, some variables pertaining to education in particular has been severely compromised due to the overwhelmingly abundant number of missing values. Otherwise, most variables have consistent and usable data that can be properly quantified.

# Summarize key parameters of the dataset
summary(salaries)
  timestamp           company             level              title           totalyearlycompensation
 Length:62642       Length:62642       Length:62642       Length:62642       Min.   :  10000        
 Class :character   Class :character   Class :character   Class :character   1st Qu.: 135000        
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Median : 188000        
                                                                             Mean   : 216300        
                                                                             3rd Qu.: 264000        
                                                                             Max.   :4980000        
                                                                                                    
   location         yearsofexperience yearsatcompany       tag              basesalary     
 Length:62642       Min.   : 0.000    Min.   : 0.000   Length:62642       Min.   :      0  
 Class :character   1st Qu.: 3.000    1st Qu.: 0.000   Class :character   1st Qu.: 108000  
 Mode  :character   Median : 6.000    Median : 2.000   Mode  :character   Median : 140000  
                    Mean   : 7.204    Mean   : 2.702                      Mean   : 136687  
                    3rd Qu.:10.000    3rd Qu.: 4.000                      3rd Qu.: 170000  
                    Max.   :69.000    Max.   :69.000                      Max.   :1659870  
                                                                                           
 stockgrantvalue       bonus            gender          otherdetails           cityid          dmaid      
 Min.   :      0   Min.   :      0   Length:62642       Length:62642       Min.   :    0   Min.   :  0.0  
 1st Qu.:      0   1st Qu.:   1000   Class :character   Class :character   1st Qu.: 7369   1st Qu.:506.0  
 Median :  25000   Median :  14000   Mode  :character   Mode  :character   Median : 7839   Median :807.0  
 Mean   :  51486   Mean   :  19335                                         Mean   : 9856   Mean   :616.1  
 3rd Qu.:  65000   3rd Qu.:  26000                                         3rd Qu.:11521   3rd Qu.:807.0  
 Max.   :2800000   Max.   :1000000                                         Max.   :47926   Max.   :881.0  
                                                                                           NA's   :2      
   rowNumber     Masters_Degree   Bachelors_Degree Doctorate_Degree    Highschool        Some_College     
 Min.   :    1   Min.   :0.0000   Min.   :0.0000   Min.   :0.00000   Min.   :0.000000   Min.   :0.000000  
 1st Qu.:20069   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.00000   1st Qu.:0.000000   1st Qu.:0.000000  
 Median :42019   Median :0.0000   Median :0.0000   Median :0.00000   Median :0.000000   Median :0.000000  
 Mean   :41695   Mean   :0.2457   Mean   :0.2012   Mean   :0.02878   Mean   :0.005108   Mean   :0.005667  
 3rd Qu.:63022   3rd Qu.:0.0000   3rd Qu.:0.0000   3rd Qu.:0.00000   3rd Qu.:0.000000   3rd Qu.:0.000000  
 Max.   :83875   Max.   :1.0000   Max.   :1.0000   Max.   :1.00000   Max.   :1.000000   Max.   :1.000000  
                                                                                                          
   Race_Asian       Race_White     Race_Two_Or_More    Race_Black      Race_Hispanic         Race          
 Min.   :0.0000   Min.   :0.0000   Min.   :0.00000   Min.   :0.00000   Min.   :0.00000   Length:62642      
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.00000   1st Qu.:0.00000   1st Qu.:0.00000   Class :character  
 Median :0.0000   Median :0.0000   Median :0.00000   Median :0.00000   Median :0.00000   Mode  :character  
 Mean   :0.1879   Mean   :0.1282   Mean   :0.01283   Mean   :0.01102   Mean   :0.01804                     
 3rd Qu.:0.0000   3rd Qu.:0.0000   3rd Qu.:0.00000   3rd Qu.:0.00000   3rd Qu.:0.00000                     
 Max.   :1.0000   Max.   :1.0000   Max.   :1.00000   Max.   :1.00000   Max.   :1.00000                     
                                                                                                           
  Education        
 Length:62642      
 Class :character  
 Mode  :character  
                   
                   
                   
                   

Data Cleaning

As discussed above, although the data points themselves are present, some of them have been reocrded in a format that proves difficult to run analysis efficiently. To that end, the following procedures are done in order to clean the data points to render them comparatively more usable for effective analysis. Notably, some variable names are in camelCase, such as rowNumber, and most are in snake_case. A simple solution is to make follow the conventions of the majority. Consequently, given that most of the data values are written in snake_case, the format where each space is replaced by (_) instead, the values will all be standardized into snake_case. Additionally, from the summaries list, the data includes a variety of information pertaining to each variable. For example, the min and max, the other quartiles, mean, and NA values (if applicable), are all shown. While this certainly is useful information, it is very easy to get overwhelmed very quickly, so at this point, we believe that it is sufficient to trim down on some of the information depictions until the latter stages of the analysis.

salaries <- salaries%>%
  clean_names("snake") #Make them all snake_case
head(salaries)

The next item on the list for cleaning is the locations variable. Due to the nature of the data set being gathered from volunteering subjects, in lieu of a strictly regimented structure where the surveys/questionnaires limit the format of an answer, the input values for the locations variable subsequently has some of the most frequent discrepancies among its values. As a result, a preliminary clean up procedure is in order to, once again, standardize the values for effective analysis. The initial step was to broadly encompass the values into a (city, state) format. However, running the following line of code renders warnings. As, the data set contains location values that are not formatted this way and also formatted in a way that lists the country name as well. For instance, (city name, state name, country name). As aforementioned in the introduction, location values outside of the US are values that were unnecessary, and were promptly eliminated.

# Clean up locations
salaries <- salaries%>%
  separate(location, 
           into = c("city", "state"), 
           sep= ",",
           convert = TRUE)
Warning: Expected 2 pieces. Additional pieces discarded in 9802 rows [19, 34, 92, 107, 115, 117, 125, 172, 213, 214, 215, 216, 231, 238, 313, 317, 321, 331, 333, 394, ...].

After removing any observation that is outside of the US, the next task is to categorize the location values of the US values. As discussed earlier, since the aims of this analysis requires a division of the locations into macro-geographic regions, the four categories are created: West, Midwest, Northeast, and South. In conjunction to creating the regional groupings, the data values are also modified to list the official state abbreviations rather than their respective full state names, for the sake of convenience.

# Organize all of the US locations into 4 big districts: West, Midwest, Northeast, South
salaries <- salaries%>%
  filter(state == " AL" | state == " AR" | state == " AZ" | state == " CA" | state == " CO" | state == " CT" | state == " FL" | state == " GA" | state == " HI" | state == " IA" | state == " ID" | state == " IL" | state == " IN" | state == " KS" | state == " KY" | state == " LA" | state == " MA" | state == " MD" | state == " ME" | state == " MI" | state == " MN" | state == " MO" | state == " MS" | state == " MT" | state == " NC" | state == " ND" | state == " NE" | state == " NH" | state == " NJ" | state == " NM" | state == " NY" | state == " OH" | state == " OK" | state == " OR" | state == " PA" | state == " RI"| state == " SC" | state == " TN" | state == " TX" | state == " UT" | state == " VA" | state == " VT" | state == " WA" | state == " WI" | state == " WV" | state == " WY")

state_abbs <- c(" AL" = "The South", " AR" = "The South", " AZ" = "The West", " CA" = "The West", " CO" = "The West", " CT" = "The Northeast", " FL" = "The South", " GA" = "The South", " HI" = "The West", " IA" = "The Midwest", " ID" = "The West", " IL" = "The Midwest", " IN" = "The Midwest", " KS" = "The Midwest", " KY" = "The South", " LA" = "The South", " MA" = "The Northeast", " MD" = "The South", " ME" = "The Northeast", " MI" = "The Midwest", " MN" = "The Midwest", " MO" = "The Midwest", " MS" = "The South", " MT" = "The West", " NC" = "The South", " ND" = "The Midwest", " NE" = "The Midwest", " NH" = "The Northeast", " NJ" = "The Northeast", " NM" = "The West", " NY" = "The Northeast", " OH" = "The Midwest", " OK" = "The South", " OR" = "The West", " PA" = "The Northeast", " RI" = "The Northeast", " SC" = "The South", " TN" = "The South", " TX" = "The South", " UT" = "The West", " VA" = "The South", " VT" = "The Northeast", " WA" = "The West", " WI" = "The Midwest", " WV" = "The South", " WY" = "The West")
salaries_recode <- salaries %>%
  mutate(state = recode(state, !!!state_abbs)) #Mutate this change to the original state variable

Since among the various variables, we chose to focus on yearly compensation, the total amount that an individual receives in a year from their employee. This coupled with other variables such as the state, and their years of experience (in general), gender, and their title - which denotes their position within the company - were chosen to run a rudimentary analysis. We chose these variables due to the fact that they best encapsulated our interests as they seemed like the most visible variables out of the entire data set.

#Select intersting variables
salaries <- salaries%>%
  select(totalyearlycompensation,yearsofexperience,gender,title, state)

As such to that end, we strove to visualize the yearly compensation in the form of a boxplot to provide some preliminary basis of understanding. With the visualization of the boxplot this definitely provided aid as to which direction our analysis should focus on.

# Boxplot about total yearly compensation
salaries%>%
ggplot(aes(x=totalyearlycompensation))+
  geom_boxplot()

Question 1: Is there an association between average yearly compensation and location?

Given that this is the primary question that we seek to scrutinize, a visualization of this the relationship between salary, formally the total yearly compensation and location is pertinent. To better understand the issue at stake, the following plots a graph showcasing the density, the frequency, per salary amount, respective to their geographic locations. Where the x-axis is the total yearly compensation, y-axis is the density, or frequency, and the legend depicts the colors of the respective regions.

The following visualization clearly indicates that there is a pretty significant disparity in the total yearly compensation between the four regions. Where the West is clearly illustrated to have the most number of engineers on almost all levels, except towards the lower end of the salary. Overall, the Midwest is shown to have the highest number of engineers at the lower levels while being lower at almost all levels among the four regions. Another critical point is that the “peak”, the highest frequency of salary per region varies quite significantly, where the highest to lowest is as follows: West, Northeast, South, Midwest. To sum up, this visualization clearly encapsulated our preliminary hypothesis that there would be some form of salary discrepancy across the regions of the US.

plot1 <- ggplot(salaries_recode, aes(x = totalyearlycompensation, color = state)) + geom_density() + # density plot
xlim(0, 1e+06) +
xlab("Total Yearly Compensation")+
  ylab("Density")+
  ggtitle("The Relationship Between Total Yearly Compensation and Location")
plot1

Question 2: Is there an association between the years of experience and total compensation, in the purview of gender?

Now that the discrepancy between the regions has been established, we proceeded to hypothesize why the discrepancies exist. And one of the first variables that deemed to be potentially responsible was the total years of experience. To be specific, we hypothesized that many the varying regions had varying roles fulfilling their niches within the broader IT industry. In that, for example, the West predominantly was the “go-to” for senior/seasoned personnel, while regions such as the South and Midwest were the entry-level regions for fresh college grads or newcomers to the industry. If the hypothesis was indeed true, then the data visualization would necessarily portray that the higher-average salary regions would be predominately have a more seasoned constituency.

However, before this could be tested, one key assumption needed to be tested: the assumption that whether total work experience, on average, tend to influence total yearly compensation. As such in order to test this key assumption, we decided to create a scatterplot to illustrate the association between total yearly compensation and total years of experience.The x-axis is the total years of experience, the y-axis is the total yearly compensation, and the legend includes a differentiation between the genders by their denoted respective colors. Naturally, this means that exclusion of observations that do not have data on gender are necessary.

Gender was originally added to this visualization to provide the stepping stone for another potential inquiry into a different hypothesis similar to the one stated above. An assumption to check if any of the regions have a skewed population in terms of their workforce that could influence the total yearly compensation insofar as to yield a disparity as seen in question 1.

Unfortunately, overall, the key assumption that we sought to scrutinize did not yield any statistically significant correlations. Furthermore, due to the comparatively dearth of female gender data values, any assumptions regarding the role of gender has also been rendered inconclusive.

salaries_2 <- salaries %>%
  drop_na(gender)%>% #Exclude observations without a gender data
  filter(gender == "Male"|gender=="Female")%>%
  filter(!is.na(totalyearlycompensation))
  
plot2 <-plot_ly(data = salaries_2, 
        x = ~yearsofexperience, 
        y= ~totalyearlycompensation)%>%
  add_markers(color = ~gender)%>%
  layout(title = "Association Between Years of Service and Total Yearly Compensation",xaxis = list(title = 'Years of Service'), 
         yaxis = list(title = 'Total Yearly Compensation'))
  
plot2
Warning: minimal value for n is 3, returning requested palette with 3 different levels
Warning: minimal value for n is 3, returning requested palette with 3 different levels
Warning: minimal value for n is 3, returning requested palette with 3 different levels
Warning: minimal value for n is 3, returning requested palette with 3 different levels

Question 3: Is there an association between years of experience and location?

Although the key assumption as to whether total years of experience and total yearly compensation had any impactful correlation was rendered moot in the question above, an alternative direction was proposed. A direction in which that reversed the conditional, “correlational”, relationship between the two variables. What if, instead of assuming that greater the experience, the greater the compensation, there was an alternative cause, a confounder, that influences the salary levels? This could be shown to have some degree of truth to it, if, the visualization of the total years of experience and location provide a paradoxical relationship to the one portrayed in question 1.

The following visualization proved to fit just that, where the West had the lowest total number of engineers in total, and in almost all bandwidths of experience years. Whereas, comparatively, the Midwest, Northeast, and South, respectively, all had higher frequencies in most bandwidths juxtaposed to the West. Although this visualization alone does not provide any definitive proof that the original hypothesis on experience and compensation being invalid, it does provide definitive proof that there is some form of a confounder that influences the relationship.

plot3 <- ggplot(salaries_recode, aes(x = yearsofexperience, color = state)) + geom_histogram() +
xlab("Years Of Experience")+
  ylab("Density")+
  ggtitle("The Relationship Between Years of Experience and Location")# density plot

plot3

Conclusion & Implications

To conclude, through the scrutinizing three principal questions in the hopes of answering the salary discrepancy between the various regions of the US has proved inconclusive, there is strong evidence to indicate that there is a potential confounder that could be at play. Truthfully, one of the core questions that we originally anticipated to analyze was the educational aspect of the data set. However, upon discovery, to our dismay, the vast majority of the education data values were empty. We believed that, from the start, that the educational differences impacting the salaries among the regions to be the most chiefly pertinent question. Unfortunately, due to the lack of available usable data, this avenue of approach was disbarred.

Moving forward, however, we envision that we will modify the hypothesis formulation format. As to address the caveats surrounding the variable in question via extrapolating data with potential outside source interchanges. Ultimately, this would mean that we would slowly build our way up to reach an analysis that encompasses the core variables that we found to be the most pertinent while examining this data set. Subsequently enabling us to employ a an approach vector that, hopefully, will not be stopped dead in its tracks due to the lack of sufficient data values. All in all, this exercise provided an opportunity to garner valuable insight and comprehend the exigencies of when data values are lacking.

Cost of Living Exploration

col_index = read.csv(file = '/Users/alvinjiao/Desktop/QTM 302W/Cost_of_living_index.csv')
col_index
col_index1 <- col_index %>%
  mutate(
    City = as.character(City),
    City_Name = str_split(City, ", ", simplify = TRUE)[, 1],
    State = str_split(City, ", ", simplify = TRUE)[, 2],
    Country = str_split(City, ", ", simplify = TRUE)[, 3]
  ) %>%
  select(-City)
us_index <- subset(col_index1, Country == "United States")
# Mapping state initials to regions
region_mapping <- c(
  "NY" = "The Northeast", "CA" = "The West", "HI" = "The West", "AK" = "The West", "DC" = "The South",
  "SC" = "The South", "WA" = "The West", "NJ" = "The Northeast", "MA" = "The Northeast", "CT" = "The Northeast",
  "PA" = "The Northeast", "IL" = "The Midwest", "CO" = "The West", "VT" = "The Northeast", "FL" = "The South",
  "ME" = "The Northeast", "OR" = "The West", "MD" = "The South", "LA" = "The South", "NC" = "The South", 
  "MN" = "The Midwest", "GA" = "The South", "AL" = "The South", "IN" = "The Midwest", "TX" = "The South",
  "OH" = "The Midwest", "MO" = "The Midwest", "WI" = "The Midwest", "TN" = "The South", "VA" = "The South",
  "MI" = "The Midwest", "NV" = "The West", "AR" = "The South", "NM" = "The West", "AZ" = "The West", "KS" = "The Midwest",
  "UT" = "The West", "OK" = "The South", "IA" = "The Midwest", "KY" = "The South", "ID" = "The West"
)

# Assuming your dataset is named "us_index"
us_index_r <- us_index %>%
  mutate(
    Regions = case_when(
      State %in% names(region_mapping) ~ region_mapping[State],
      TRUE ~ "Unknown"  
    )
  )
# Assuming your dataset is named "us_index_r"
# Assuming your mapping is named "region_mapping"

# Plotting the density
ggplot(us_index_r, aes(x = Cost.of.Living.Index, fill = Regions)) +
  geom_density(alpha = 0.5) +
  scale_fill_manual(values = c(
    "The Northeast" = "blue", 
    "The West" = "green", 
    "The Midwest" = "orange", 
    "The South" = "red"
  )) +
  theme_minimal() +
  labs(
    title = "Density Plot of Cost of Living Index by Regions",
    x = "Cost of Living Index",
    y = "Density"
  )

Salary vs. Majors vs. Gender Exploration

library(ggplot2)

# Order the dataset by Mid.Career.Median.Salary
Wage_sorted <- Wage[order(Wage$Mid.Career.Median.Salary, decreasing = TRUE), ]

# Extract the top ten and bottom ten rows
top_ten <- head(Wage_sorted, 10)
bottom_ten <- tail(Wage_sorted, 10)

# Create a function to generate the bar plot
plot_major_salary <- function(data, title) {
  ggplot(data, aes(x = reorder(Undergraduate.Major, Mid.Career.Median.Salary), y = Mid.Career.Median.Salary)) +
    geom_bar(stat = "identity", fill = "skyblue") +
    coord_flip() +
    theme_minimal() +
    labs(
      title = title,
      x = "Undergraduate Major",
      y = "Mid-Career Median Salary"
    )
}

# Plot the top ten highest
plot_top_ten <- plot_major_salary(top_ten, "Top Ten Highest Mid-Career Median Salaries")

# Plot the bottom ten
plot_bottom_ten <- plot_major_salary(bottom_ten, "Bottom Ten Mid-Career Median Salaries")

# Display the plots side by side
library(gridExtra)
grid.arrange(plot_top_ten, plot_bottom_ten, ncol = 2)

grad = read.csv('recent-grads.csv')
grad_sorted <- grad[order(grad$ShareWomen, decreasing = TRUE), ]

# Extract the top ten and bottom ten rows
top_ten <- head(grad_sorted, 10)
bottom_ten <- tail(grad_sorted, 10)

# Create a function to generate the bar plot
plot_major_sharewomen <- function(data, title) {
  ggplot(data, aes(x = reorder(Major, ShareWomen), y = ShareWomen, fill = `Major_category`)) +
    geom_bar(stat = "identity") +
    coord_flip() +
    theme_minimal() +
    labs(
      title = title,
      x = "Major",
      y = "ShareWomen"
    )
}

# Plot the top ten highest
plot_top_ten <- plot_major_sharewomen(top_ten, "Top Ten Highest ShareWomen")

# Plot the bottom ten
plot_bottom_ten <- plot_major_sharewomen(bottom_ten, "Bottom Ten ShareWomen")

# Display the plots side by side
library(gridExtra)
grid.arrange(plot_top_ten, plot_bottom_ten, ncol = 1)

LS0tCnRpdGxlOiAiRURBIE5vdGVib29rIERyYWZ0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIEludHJvZHVjdGlvbgoKYGBge3J9CiMgTG9hZCBwYWNrYWdlcyB3ZSBhcmUgZ29pbmcgdG8gdXNlCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSwgamFuaXRvciwgcGxvdGx5LCBkYXRhTWV0YSwgUkNvbG9yQnJld2VyLCBncmlkRXh0cmEpCmBgYAoKYGBge3J9CiMgUmVhZCB0aGUgZGF0YSBhbmQgc3RvcmUgaXQgdG8gJ3NhbGFyaWVzJwpzYWxhcmllcyA8LSByZWFkLmNzdihmaWxlID0gJy9Vc2Vycy9hbHZpbmppYW8vRGVza3RvcC9RVE0gMzAyVy9TYWxhcnkuY3N2JykKaGVhZChzYWxhcmllcykKYGBgCgojIERhdGEgRXhwbG9yaW5nCgpUaGlzIGRhdGEsIGJyb2FkbHksIHNwZWFraW5nIGhhcyBpbmZvcm1hdGlvbiBvZiBkYXRhIHNjaWVuY2UgZW1wbG95ZWVzIGFuZCB0aGVpciBzYWxhcmllcyBhdmFpbGFibGUgb24gZnJlZSBkYXRhLW9yaWVudGVkIHBsYXRmb3JtcyBzdWNoIGFzIEthZ2dsZSAobm90ZTogdGhlIGF1dGhvciBvZiB0aGUgb3JpZ2luYWwgc291cmNlIG9mIHRoZSBkYXRhIGhhcyBqdXN0IHJlY2VudGx5IHN3aXRjaGVkIHRoZWlyIHByb2ZpbGUgaW50byBwcml2YXRlIG1vZGUsIHNvIGFuIGFsdGVybmF0ZSBsaW5rIHdpbGwgYmUgdXNlZCBhcyBhbiBzdWJzdGl0dXRlOiA8aHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9jb2RlL2ZlYmllYy9kYXRhLXNjaWVuY2UtYW5kLXRlY2gtc2FsYXJpZXMtdmlzdWFsaXphdGlvbi9ub3RlYm9vaz4pLiBUbyBiZSBzcGVjaWZpYywgc29tZSBvZiB0aGUgbWFpbiB2YXJpYWJsZXMgdGhhdCBhcmUgcGFydCBvZiB0aGlzIGRhdGEgc2V0IGluY2x1ZGUgYnV0IG5vdCBsaW1pdGVkIHRvOiB5ZWFybHkgY29tcGVuc2F0aW9uLCByYWNlLCBmaW5hbCBlZHVjYXRpb24gbGV2ZWwsIHllYXJzIG9mIGV4cGVyaWVuY2UsIG51bWJlciBvZiB5ZWFycyBhdCB0aGUgY3VycmVudCBjb21wYW55LCBhbmQgZ2VvZ3JhcGhpYyBsb2NhdGlvbi4gVGhpcyBkYXRhIHNldCB3YXMgY2hvc2VuIGR1ZSB0byB0aGUgaW5jcmVhc2luZ2x5IHNpZ25pZmljYW50IHJvbGUgZGF0YSBsaXRlcmFjeSBhbmQgYW5hbHlzaXMgcGxheXMgaW4gdGhlIG1vZGVybiB3b3JsZC4gU2ltcGx5IHB1dCwgdGhlIGltcG9ydGFuY2Ugb2YgZGF0YSBpcyBub3Qgb25seSBqdXN0IHN0cmljdGx5IGxpbWl0ZWQgdG8gdGhlIGFjYWRlbWljIGZpZWxkIGJ1dCBoYXMgdHJhbnNmb3JtZWQgdG8gYmUgYSBtYWpvciBpbnRlZ3JhbCBwYXJ0IHRoYXQgaXMgbm93IGZ1bmRhbWVudGFsbHkgaW50ZXJsaW5rZWQgd2l0aCBqb2JzLiBBcyB0aGUgY29udGludWVkIHJlbGV2YW5jZSBvZiBkYXRhIGlzIGdyb3dpbmcgc3Ryb25nZXIsIHRoZSBkZXNpcmUgZm9yIGVudGl0aWVzIC0gZW1wbG95ZXJzIC0gdG8gbG9vayBza2lsbGVkIHBlcnNvbm5lbCBjYW4gYmUgYmVzdCBzZWVuIGJ5IHRoZWlyIHdpbGxpbmcgdG8gY29tcGVuc2F0ZSBhcHRseSBza2lsbGVkIHBlcnNvbm5lbC4gR3JhbnRlZCwgZXZlbiB3aXRoIHRoZSBzYW1lIGZpZWxkIG9mIGV4cGVydGlzZSwgdGhlcmUgYXJlIGZhY3RvcnMgdGhhdCBjb250cmlidXRlIGRpc3Bhcml0eS4gUHJlY2lzZWx5LCB0byB0aGF0IGVuZCwgYnkgYW5hbHl6aW5nIHRoaXMgZGF0YSBzZXQsIHRoZSBvYmplY3RpdmUgaXMgdG8gZGVwaWN0IHNvbWUgcmVsZXZhbnQgYW5kIGluZm9ybWF0aXZlIGluc2lnaHQgaW50byBzb21lIG9mIHRoZSBmYWN0b3JzIHRoYXQgbWlnaHQgaW5mbHVlbmNlIGEgc2FsYXJ5IG9mIGFuIGluZGl2aWR1YWwuIFRoZXJlYnkgZ2F0aGVyaW5nIGEgbXVjaCBtb3JlIGhvbGlzdGljIHZpZXcgb2YgZmFjdG9ycyB0aGF0IGNvbnRyaWJ1dGUgdG8gdGhlIGRpc3Bhcml0eSBhbmQgdmFyaWF0aW9ucyBhbW9uZyB0aGUgcGVyc29ubmVsIHdpdGhpbiBvbmUgaW5kdXN0cnkuIAoKVGhlIHByaW5jaXBhbCBhaW0gYmVoaW5kIHRoaXMgYW5hbHlzaXMgaXMgdG8gc2NydXRpbml6ZSBhcyB0byB3aHkgdG90YWwgeWVhcmx5IGNvbXBlbnNhdGlvbiwgaGVuY2Vmb3J0aCByZWZlcnJlZCB0byBhcyAic2FsYXJ5IiwgZGlmZmVyIGZyb20gdGhlIHZhcmlvdXMgcmVnaW9ucyBvZiB0aGUgVW5pdGVkIFN0YXRlcy4gSW4gb3JkZXIgdG8gYWNoaWV2ZSB0aGlzIGV4cGxvcmF0aW9uIG9mIGRhdGEsIHRoZSBzY29wZSBvZiB0aGUgZGF0YSwgZmlyc3QgYW5kIGZvcmVtb3N0IHdpbGwgYmUgbGltaXRlZCB0byBpbmNsdWRlIG9ubHkgdGhlIHZhbHVlcyB0aGF0IHBlcnRhaW4gdG8gdGhlIFVTLiBTZWNvbmQsIGFsdGhvdWdoIHRoaXMgd2lsbCBiZSBkaXNjdXNzZWQgbW9yZSBpbi1kZXB0aCBpbiB0aGUgY29ycmVzcG9uZGluZyBzZWN0aW9uIGxhdGVyLCB0aGUgcmVnaW9ucyB0aGF0IHdpbGwgYmUgdXNlZCBmb3IgdGhlIGR1cmF0aW9uIG9mIHRoaXMgYW5hbHlzaXMgYXJlIGFzIGZvbGxvd3M6IE5vcnRoZWFzdCwgTWlkd2VzdCwgU291dGgsIGFuZCBXZXN0LiBMYXN0bHksIHRoZSBjZW50cmFsIGxlbnMgdGhhdCB0aGlzIGFuYWx5c2lzIHdpbGwgYmUgY29uZHVjdGVkIHVuZGVyIGlzIHZpYSB0aGUgbG9jYXRpb24gaW4gb3JkZXIgdG8gc2NydXRpbml6ZSB3aHkgdGhlcmUgYXJlIHNhbGFyeSB2YXJpYXRpb25zIGFtb25nIHRoZSBkaWZmZXJlbnQgcmVnaW9ucyBvZiBvbmUgY291bnRyeSAtIHRoZSBVUy4gVG8gdGhhdCBlbmQsIGRpc2N1c3Npb25zIG9mIG90aGVyIHZhcmlhYmxlcyB0aGF0IG1pZ2h0IGV4cGxhaW4gdGhlIGRpZmZlcmVuY2VzIGluIHRoZSByZWdpb25hbGx5IGdyb3VwZWQgbG9jYXRpb25zIHdpbGwgYmUgY29uZHVjdGVkIGVzcGVjaWFsbHkgdGhyb3VnaCBleHBsb3JpbmcgdGhlIHRvdGFsIGV4cGVyaWVuY2UgdmFyaWFibGUgaW4gcGFydGljdWxhci4KCmBgYHtyfQojIENoZWNrIHdoYXQgY2xhc3NlcyB0aGUgdmFyaWFibGVzIGFyZSBpbgpzdHIoc2FsYXJpZXMpCiMgQ2hlY2sgaWYgdGhlYXIgYXJlIGR1cGxpY2F0ZWQgb2JzZXJ2YXRpb25zCmdldF9kdXBlcyhzYWxhcmllcykgI0NoZWNrIGZvciBkdXBsaWNhdGVzOiBOT05FIQpgYGAKClRoZSBkYXRhIHNldCBpbmNsdWRlcyA2MjY0MiBvYnNlcnZhdGlvbnMgYW5kIDI5IGNvbHVtbnMgdG8gc3RvcmUgdGhlbS4gVGhlIGNvbHVtbiB2YXJpYWJsZXMgYXJlIGlsbHVzdHJhdGVkIGluIHRoZSBkYXRhIGRpY3Rpb25hcnkuIFNvbWUgb2Ygd2hpY2ggaGF2ZSBiZWVuIGFscmVhZHkgbWVudGlvbmVkIGluIHRoZSBwcmlvciBzZWN0aW9uLiBUaGUgZGF0YSBzZXQgaXMgcGFydGlhbGx5IGNsZWFuLCBmb3IgaXRzIHZhcmlhYmxlIHR5cGVzIGFyZSBjb3JyZWN0IGFuZCBpdCBkb2VzIG5vdCBoYXZlIGFueSBkdXBsaWNhdGVzLiBIb3dldmVyLCBpdCBpcyBub3QgY2xlYW4gaW4gdGVybXMgb2YgdmFyaWFibGUgbmFtZXMgYW5kIG1pc3NpbmcgdmFsdWVzLiBBbHRob3VnaCB0aGlzIHdpbGwgYmUgYWRkcmVzc2VkIG9uY2UgbW9yZSB0b3dhcmRzIHRoZSBlbmQgb2YgdGhlIGFuYWx5c2lzLCBzb21lIHZhcmlhYmxlcyBwZXJ0YWluaW5nIHRvIGVkdWNhdGlvbiBpbiBwYXJ0aWN1bGFyIGhhcyBiZWVuIHNldmVyZWx5IGNvbXByb21pc2VkIGR1ZSB0byB0aGUgb3ZlcndoZWxtaW5nbHkgYWJ1bmRhbnQgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzLiBPdGhlcndpc2UsIG1vc3QgdmFyaWFibGVzIGhhdmUgY29uc2lzdGVudCBhbmQgdXNhYmxlIGRhdGEgdGhhdCBjYW4gYmUgcHJvcGVybHkgcXVhbnRpZmllZC4KCmBgYHtyfQojIFN1bW1hcml6ZSBrZXkgcGFyYW1ldGVycyBvZiB0aGUgZGF0YXNldApzdW1tYXJ5KHNhbGFyaWVzKQpgYGAKCiMgRGF0YSBDbGVhbmluZwoKQXMgZGlzY3Vzc2VkIGFib3ZlLCBhbHRob3VnaCB0aGUgZGF0YSBwb2ludHMgdGhlbXNlbHZlcyBhcmUgcHJlc2VudCwgc29tZSBvZiB0aGVtIGhhdmUgYmVlbiByZW9jcmRlZCBpbiBhIGZvcm1hdCB0aGF0IHByb3ZlcyBkaWZmaWN1bHQgdG8gcnVuIGFuYWx5c2lzIGVmZmljaWVudGx5LiBUbyB0aGF0IGVuZCwgdGhlIGZvbGxvd2luZyBwcm9jZWR1cmVzIGFyZSBkb25lIGluIG9yZGVyIHRvIGNsZWFuIHRoZSBkYXRhIHBvaW50cyB0byByZW5kZXIgdGhlbSBjb21wYXJhdGl2ZWx5IG1vcmUgdXNhYmxlIGZvciBlZmZlY3RpdmUgYW5hbHlzaXMuIE5vdGFibHksIHNvbWUgdmFyaWFibGUgbmFtZXMgYXJlIGluIGNhbWVsQ2FzZSwgc3VjaCBhcyByb3dOdW1iZXIsIGFuZCBtb3N0IGFyZSBpbiBzbmFrZV9jYXNlLiBBIHNpbXBsZSBzb2x1dGlvbiBpcyB0byBtYWtlIGZvbGxvdyB0aGUgY29udmVudGlvbnMgb2YgdGhlIG1ham9yaXR5LiBDb25zZXF1ZW50bHksIGdpdmVuIHRoYXQgbW9zdCBvZiB0aGUgZGF0YSB2YWx1ZXMgYXJlIHdyaXR0ZW4gaW4gc25ha2VfY2FzZSwgdGhlIGZvcm1hdCB3aGVyZSBlYWNoIHNwYWNlIGlzIHJlcGxhY2VkIGJ5IChfKSBpbnN0ZWFkLCB0aGUgdmFsdWVzIHdpbGwgYWxsIGJlIHN0YW5kYXJkaXplZCBpbnRvIHNuYWtlX2Nhc2UuIEFkZGl0aW9uYWxseSwgZnJvbSB0aGUgc3VtbWFyaWVzIGxpc3QsIHRoZSBkYXRhIGluY2x1ZGVzIGEgdmFyaWV0eSBvZiBpbmZvcm1hdGlvbiBwZXJ0YWluaW5nIHRvIGVhY2ggdmFyaWFibGUuIEZvciBleGFtcGxlLCB0aGUgbWluIGFuZCBtYXgsIHRoZSBvdGhlciBxdWFydGlsZXMsIG1lYW4sIGFuZCBOQSB2YWx1ZXMgKGlmIGFwcGxpY2FibGUpLCBhcmUgYWxsIHNob3duLiBXaGlsZSB0aGlzIGNlcnRhaW5seSBpcyB1c2VmdWwgaW5mb3JtYXRpb24sIGl0IGlzIHZlcnkgZWFzeSB0byBnZXQgb3ZlcndoZWxtZWQgdmVyeSBxdWlja2x5LCBzbyBhdCB0aGlzIHBvaW50LCB3ZSBiZWxpZXZlIHRoYXQgaXQgaXMgc3VmZmljaWVudCB0byB0cmltIGRvd24gb24gc29tZSBvZiB0aGUgaW5mb3JtYXRpb24gZGVwaWN0aW9ucyB1bnRpbCB0aGUgbGF0dGVyIHN0YWdlcyBvZiB0aGUgYW5hbHlzaXMuCgpgYGB7cn0Kc2FsYXJpZXMgPC0gc2FsYXJpZXMlPiUKICBjbGVhbl9uYW1lcygic25ha2UiKSAjTWFrZSB0aGVtIGFsbCBzbmFrZV9jYXNlCmhlYWQoc2FsYXJpZXMpCmBgYAoKVGhlIG5leHQgaXRlbSBvbiB0aGUgbGlzdCBmb3IgY2xlYW5pbmcgaXMgdGhlIGxvY2F0aW9ucyB2YXJpYWJsZS4gRHVlIHRvIHRoZSBuYXR1cmUgb2YgdGhlIGRhdGEgc2V0IGJlaW5nIGdhdGhlcmVkIGZyb20gdm9sdW50ZWVyaW5nIHN1YmplY3RzLCBpbiBsaWV1IG9mIGEgc3RyaWN0bHkgcmVnaW1lbnRlZCBzdHJ1Y3R1cmUgd2hlcmUgdGhlIHN1cnZleXMvcXVlc3Rpb25uYWlyZXMgbGltaXQgdGhlIGZvcm1hdCBvZiBhbiBhbnN3ZXIsIHRoZSBpbnB1dCB2YWx1ZXMgZm9yIHRoZSBsb2NhdGlvbnMgdmFyaWFibGUgc3Vic2VxdWVudGx5IGhhcyBzb21lIG9mIHRoZSBtb3N0IGZyZXF1ZW50IGRpc2NyZXBhbmNpZXMgYW1vbmcgaXRzIHZhbHVlcy4gQXMgYSByZXN1bHQsIGEgcHJlbGltaW5hcnkgY2xlYW4gdXAgcHJvY2VkdXJlIGlzIGluIG9yZGVyIHRvLCBvbmNlIGFnYWluLCBzdGFuZGFyZGl6ZSB0aGUgdmFsdWVzIGZvciBlZmZlY3RpdmUgYW5hbHlzaXMuIFRoZSBpbml0aWFsIHN0ZXAgd2FzIHRvIGJyb2FkbHkgZW5jb21wYXNzIHRoZSB2YWx1ZXMgaW50byBhIChjaXR5LCBzdGF0ZSkgZm9ybWF0LiBIb3dldmVyLCBydW5uaW5nIHRoZSBmb2xsb3dpbmcgbGluZSBvZiBjb2RlIHJlbmRlcnMgd2FybmluZ3MuIEFzLCB0aGUgZGF0YSBzZXQgY29udGFpbnMgbG9jYXRpb24gdmFsdWVzIHRoYXQgYXJlIG5vdCBmb3JtYXR0ZWQgdGhpcyB3YXkgYW5kIGFsc28gZm9ybWF0dGVkIGluIGEgd2F5IHRoYXQgbGlzdHMgdGhlIGNvdW50cnkgbmFtZSBhcyB3ZWxsLiBGb3IgaW5zdGFuY2UsIChjaXR5IG5hbWUsIHN0YXRlIG5hbWUsIGNvdW50cnkgbmFtZSkuIEFzIGFmb3JlbWVudGlvbmVkIGluIHRoZSBpbnRyb2R1Y3Rpb24sIGxvY2F0aW9uIHZhbHVlcyBvdXRzaWRlIG9mIHRoZSBVUyBhcmUgdmFsdWVzIHRoYXQgd2VyZSB1bm5lY2Vzc2FyeSwgYW5kIHdlcmUgcHJvbXB0bHkgZWxpbWluYXRlZC4KCmBgYHtyfQojIENsZWFuIHVwIGxvY2F0aW9ucwpzYWxhcmllcyA8LSBzYWxhcmllcyU+JQogIHNlcGFyYXRlKGxvY2F0aW9uLCAKICAgICAgICAgICBpbnRvID0gYygiY2l0eSIsICJzdGF0ZSIpLCAKICAgICAgICAgICBzZXA9ICIsIiwKICAgICAgICAgICBjb252ZXJ0ID0gVFJVRSkKYGBgCgpBZnRlciByZW1vdmluZyBhbnkgb2JzZXJ2YXRpb24gdGhhdCBpcyBvdXRzaWRlIG9mIHRoZSBVUywgdGhlIG5leHQgdGFzayBpcyB0byBjYXRlZ29yaXplIHRoZSBsb2NhdGlvbiB2YWx1ZXMgb2YgdGhlIFVTIHZhbHVlcy4gQXMgZGlzY3Vzc2VkIGVhcmxpZXIsIHNpbmNlIHRoZSBhaW1zIG9mIHRoaXMgYW5hbHlzaXMgcmVxdWlyZXMgYSBkaXZpc2lvbiBvZiB0aGUgbG9jYXRpb25zIGludG8gbWFjcm8tZ2VvZ3JhcGhpYyByZWdpb25zLCB0aGUgZm91ciBjYXRlZ29yaWVzIGFyZSBjcmVhdGVkOiBXZXN0LCBNaWR3ZXN0LCBOb3J0aGVhc3QsIGFuZCBTb3V0aC4gSW4gY29uanVuY3Rpb24gdG8gY3JlYXRpbmcgdGhlIHJlZ2lvbmFsIGdyb3VwaW5ncywgdGhlIGRhdGEgdmFsdWVzIGFyZSBhbHNvIG1vZGlmaWVkIHRvIGxpc3QgdGhlIG9mZmljaWFsIHN0YXRlIGFiYnJldmlhdGlvbnMgcmF0aGVyIHRoYW4gdGhlaXIgcmVzcGVjdGl2ZSBmdWxsIHN0YXRlIG5hbWVzLCBmb3IgdGhlIHNha2Ugb2YgY29udmVuaWVuY2UuCgpgYGB7cn0KIyBPcmdhbml6ZSBhbGwgb2YgdGhlIFVTIGxvY2F0aW9ucyBpbnRvIDQgYmlnIGRpc3RyaWN0czogV2VzdCwgTWlkd2VzdCwgTm9ydGhlYXN0LCBTb3V0aApzYWxhcmllcyA8LSBzYWxhcmllcyU+JQogIGZpbHRlcihzdGF0ZSA9PSAiIEFMIiB8IHN0YXRlID09ICIgQVIiIHwgc3RhdGUgPT0gIiBBWiIgfCBzdGF0ZSA9PSAiIENBIiB8IHN0YXRlID09ICIgQ08iIHwgc3RhdGUgPT0gIiBDVCIgfCBzdGF0ZSA9PSAiIEZMIiB8IHN0YXRlID09ICIgR0EiIHwgc3RhdGUgPT0gIiBISSIgfCBzdGF0ZSA9PSAiIElBIiB8IHN0YXRlID09ICIgSUQiIHwgc3RhdGUgPT0gIiBJTCIgfCBzdGF0ZSA9PSAiIElOIiB8IHN0YXRlID09ICIgS1MiIHwgc3RhdGUgPT0gIiBLWSIgfCBzdGF0ZSA9PSAiIExBIiB8IHN0YXRlID09ICIgTUEiIHwgc3RhdGUgPT0gIiBNRCIgfCBzdGF0ZSA9PSAiIE1FIiB8IHN0YXRlID09ICIgTUkiIHwgc3RhdGUgPT0gIiBNTiIgfCBzdGF0ZSA9PSAiIE1PIiB8IHN0YXRlID09ICIgTVMiIHwgc3RhdGUgPT0gIiBNVCIgfCBzdGF0ZSA9PSAiIE5DIiB8IHN0YXRlID09ICIgTkQiIHwgc3RhdGUgPT0gIiBORSIgfCBzdGF0ZSA9PSAiIE5IIiB8IHN0YXRlID09ICIgTkoiIHwgc3RhdGUgPT0gIiBOTSIgfCBzdGF0ZSA9PSAiIE5ZIiB8IHN0YXRlID09ICIgT0giIHwgc3RhdGUgPT0gIiBPSyIgfCBzdGF0ZSA9PSAiIE9SIiB8IHN0YXRlID09ICIgUEEiIHwgc3RhdGUgPT0gIiBSSSJ8IHN0YXRlID09ICIgU0MiIHwgc3RhdGUgPT0gIiBUTiIgfCBzdGF0ZSA9PSAiIFRYIiB8IHN0YXRlID09ICIgVVQiIHwgc3RhdGUgPT0gIiBWQSIgfCBzdGF0ZSA9PSAiIFZUIiB8IHN0YXRlID09ICIgV0EiIHwgc3RhdGUgPT0gIiBXSSIgfCBzdGF0ZSA9PSAiIFdWIiB8IHN0YXRlID09ICIgV1kiKQoKc3RhdGVfYWJicyA8LSBjKCIgQUwiID0gIlRoZSBTb3V0aCIsICIgQVIiID0gIlRoZSBTb3V0aCIsICIgQVoiID0gIlRoZSBXZXN0IiwgIiBDQSIgPSAiVGhlIFdlc3QiLCAiIENPIiA9ICJUaGUgV2VzdCIsICIgQ1QiID0gIlRoZSBOb3J0aGVhc3QiLCAiIEZMIiA9ICJUaGUgU291dGgiLCAiIEdBIiA9ICJUaGUgU291dGgiLCAiIEhJIiA9ICJUaGUgV2VzdCIsICIgSUEiID0gIlRoZSBNaWR3ZXN0IiwgIiBJRCIgPSAiVGhlIFdlc3QiLCAiIElMIiA9ICJUaGUgTWlkd2VzdCIsICIgSU4iID0gIlRoZSBNaWR3ZXN0IiwgIiBLUyIgPSAiVGhlIE1pZHdlc3QiLCAiIEtZIiA9ICJUaGUgU291dGgiLCAiIExBIiA9ICJUaGUgU291dGgiLCAiIE1BIiA9ICJUaGUgTm9ydGhlYXN0IiwgIiBNRCIgPSAiVGhlIFNvdXRoIiwgIiBNRSIgPSAiVGhlIE5vcnRoZWFzdCIsICIgTUkiID0gIlRoZSBNaWR3ZXN0IiwgIiBNTiIgPSAiVGhlIE1pZHdlc3QiLCAiIE1PIiA9ICJUaGUgTWlkd2VzdCIsICIgTVMiID0gIlRoZSBTb3V0aCIsICIgTVQiID0gIlRoZSBXZXN0IiwgIiBOQyIgPSAiVGhlIFNvdXRoIiwgIiBORCIgPSAiVGhlIE1pZHdlc3QiLCAiIE5FIiA9ICJUaGUgTWlkd2VzdCIsICIgTkgiID0gIlRoZSBOb3J0aGVhc3QiLCAiIE5KIiA9ICJUaGUgTm9ydGhlYXN0IiwgIiBOTSIgPSAiVGhlIFdlc3QiLCAiIE5ZIiA9ICJUaGUgTm9ydGhlYXN0IiwgIiBPSCIgPSAiVGhlIE1pZHdlc3QiLCAiIE9LIiA9ICJUaGUgU291dGgiLCAiIE9SIiA9ICJUaGUgV2VzdCIsICIgUEEiID0gIlRoZSBOb3J0aGVhc3QiLCAiIFJJIiA9ICJUaGUgTm9ydGhlYXN0IiwgIiBTQyIgPSAiVGhlIFNvdXRoIiwgIiBUTiIgPSAiVGhlIFNvdXRoIiwgIiBUWCIgPSAiVGhlIFNvdXRoIiwgIiBVVCIgPSAiVGhlIFdlc3QiLCAiIFZBIiA9ICJUaGUgU291dGgiLCAiIFZUIiA9ICJUaGUgTm9ydGhlYXN0IiwgIiBXQSIgPSAiVGhlIFdlc3QiLCAiIFdJIiA9ICJUaGUgTWlkd2VzdCIsICIgV1YiID0gIlRoZSBTb3V0aCIsICIgV1kiID0gIlRoZSBXZXN0IikKc2FsYXJpZXNfcmVjb2RlIDwtIHNhbGFyaWVzICU+JQogIG11dGF0ZShzdGF0ZSA9IHJlY29kZShzdGF0ZSwgISEhc3RhdGVfYWJicykpICNNdXRhdGUgdGhpcyBjaGFuZ2UgdG8gdGhlIG9yaWdpbmFsIHN0YXRlIHZhcmlhYmxlCmBgYAoKU2luY2UgYW1vbmcgdGhlIHZhcmlvdXMgdmFyaWFibGVzLCB3ZSBjaG9zZSB0byBmb2N1cyBvbiB5ZWFybHkgY29tcGVuc2F0aW9uLCB0aGUgdG90YWwgYW1vdW50IHRoYXQgYW4gaW5kaXZpZHVhbCByZWNlaXZlcyBpbiBhIHllYXIgZnJvbSB0aGVpciBlbXBsb3llZS4gVGhpcyBjb3VwbGVkIHdpdGggb3RoZXIgdmFyaWFibGVzIHN1Y2ggYXMgdGhlIHN0YXRlLCBhbmQgdGhlaXIgeWVhcnMgb2YgZXhwZXJpZW5jZSAoaW4gZ2VuZXJhbCksIGdlbmRlciwgYW5kIHRoZWlyIHRpdGxlIC0gd2hpY2ggZGVub3RlcyB0aGVpciBwb3NpdGlvbiB3aXRoaW4gdGhlIGNvbXBhbnkgLSB3ZXJlIGNob3NlbiB0byBydW4gYSBydWRpbWVudGFyeSBhbmFseXNpcy4gV2UgY2hvc2UgdGhlc2UgdmFyaWFibGVzIGR1ZSB0byB0aGUgZmFjdCB0aGF0IHRoZXkgYmVzdCBlbmNhcHN1bGF0ZWQgb3VyIGludGVyZXN0cyBhcyB0aGV5IHNlZW1lZCBsaWtlIHRoZSBtb3N0IHZpc2libGUgdmFyaWFibGVzIG91dCBvZiB0aGUgZW50aXJlIGRhdGEgc2V0LgoKYGBge3J9CiNTZWxlY3QgaW50ZXJzdGluZyB2YXJpYWJsZXMKc2FsYXJpZXMgPC0gc2FsYXJpZXMlPiUKICBzZWxlY3QodG90YWx5ZWFybHljb21wZW5zYXRpb24seWVhcnNvZmV4cGVyaWVuY2UsZ2VuZGVyLHRpdGxlLCBzdGF0ZSkKYGBgCgpBcyBzdWNoIHRvIHRoYXQgZW5kLCB3ZSBzdHJvdmUgdG8gdmlzdWFsaXplIHRoZSB5ZWFybHkgY29tcGVuc2F0aW9uIGluIHRoZSBmb3JtIG9mIGEgYm94cGxvdCB0byBwcm92aWRlIHNvbWUgcHJlbGltaW5hcnkgYmFzaXMgb2YgdW5kZXJzdGFuZGluZy4gV2l0aCB0aGUgdmlzdWFsaXphdGlvbiBvZiB0aGUgYm94cGxvdCB0aGlzIGRlZmluaXRlbHkgcHJvdmlkZWQgYWlkIGFzIHRvIHdoaWNoIGRpcmVjdGlvbiBvdXIgYW5hbHlzaXMgc2hvdWxkIGZvY3VzIG9uLgoKYGBge3J9CiMgQm94cGxvdCBhYm91dCB0b3RhbCB5ZWFybHkgY29tcGVuc2F0aW9uCnNhbGFyaWVzJT4lCmdncGxvdChhZXMoeD10b3RhbHllYXJseWNvbXBlbnNhdGlvbikpKwogIGdlb21fYm94cGxvdCgpCmBgYAoKIyMjIFF1ZXN0aW9uIDE6IElzIHRoZXJlIGFuIGFzc29jaWF0aW9uIGJldHdlZW4gYXZlcmFnZSB5ZWFybHkgY29tcGVuc2F0aW9uIGFuZCBsb2NhdGlvbj8KCkdpdmVuIHRoYXQgdGhpcyBpcyB0aGUgcHJpbWFyeSBxdWVzdGlvbiB0aGF0IHdlIHNlZWsgdG8gc2NydXRpbml6ZSwgYSB2aXN1YWxpemF0aW9uIG9mIHRoaXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNhbGFyeSwgZm9ybWFsbHkgdGhlIHRvdGFsIHllYXJseSBjb21wZW5zYXRpb24gYW5kIGxvY2F0aW9uIGlzIHBlcnRpbmVudC4gVG8gYmV0dGVyIHVuZGVyc3RhbmQgdGhlIGlzc3VlIGF0IHN0YWtlLCB0aGUgZm9sbG93aW5nIHBsb3RzIGEgZ3JhcGggc2hvd2Nhc2luZyB0aGUgZGVuc2l0eSwgdGhlIGZyZXF1ZW5jeSwgcGVyIHNhbGFyeSBhbW91bnQsIHJlc3BlY3RpdmUgdG8gdGhlaXIgZ2VvZ3JhcGhpYyBsb2NhdGlvbnMuIFdoZXJlIHRoZSB4LWF4aXMgaXMgdGhlIHRvdGFsIHllYXJseSBjb21wZW5zYXRpb24sIHktYXhpcyBpcyB0aGUgZGVuc2l0eSwgb3IgZnJlcXVlbmN5LCBhbmQgdGhlIGxlZ2VuZCBkZXBpY3RzIHRoZSBjb2xvcnMgb2YgdGhlIHJlc3BlY3RpdmUgcmVnaW9ucy4gCgpUaGUgZm9sbG93aW5nIHZpc3VhbGl6YXRpb24gY2xlYXJseSBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBpcyBhIHByZXR0eSBzaWduaWZpY2FudCBkaXNwYXJpdHkgaW4gdGhlIHRvdGFsIHllYXJseSBjb21wZW5zYXRpb24gYmV0d2VlbiB0aGUgZm91ciByZWdpb25zLiBXaGVyZSB0aGUgV2VzdCBpcyBjbGVhcmx5IGlsbHVzdHJhdGVkIHRvIGhhdmUgdGhlIG1vc3QgbnVtYmVyIG9mIGVuZ2luZWVycyBvbiBhbG1vc3QgYWxsIGxldmVscywgZXhjZXB0IHRvd2FyZHMgdGhlIGxvd2VyIGVuZCBvZiB0aGUgc2FsYXJ5LiBPdmVyYWxsLCB0aGUgTWlkd2VzdCBpcyBzaG93biB0byBoYXZlIHRoZSBoaWdoZXN0IG51bWJlciBvZiBlbmdpbmVlcnMgYXQgdGhlIGxvd2VyIGxldmVscyB3aGlsZSBiZWluZyBsb3dlciBhdCBhbG1vc3QgYWxsIGxldmVscyBhbW9uZyB0aGUgZm91ciByZWdpb25zLiBBbm90aGVyIGNyaXRpY2FsIHBvaW50IGlzIHRoYXQgdGhlICJwZWFrIiwgdGhlIGhpZ2hlc3QgZnJlcXVlbmN5IG9mIHNhbGFyeSBwZXIgcmVnaW9uIHZhcmllcyBxdWl0ZSBzaWduaWZpY2FudGx5LCB3aGVyZSB0aGUgaGlnaGVzdCB0byBsb3dlc3QgaXMgYXMgZm9sbG93czogV2VzdCwgTm9ydGhlYXN0LCBTb3V0aCwgTWlkd2VzdC4gVG8gc3VtIHVwLCB0aGlzIHZpc3VhbGl6YXRpb24gY2xlYXJseSBlbmNhcHN1bGF0ZWQgb3VyIHByZWxpbWluYXJ5IGh5cG90aGVzaXMgdGhhdCB0aGVyZSB3b3VsZCBiZSBzb21lIGZvcm0gb2Ygc2FsYXJ5IGRpc2NyZXBhbmN5IGFjcm9zcyB0aGUgcmVnaW9ucyBvZiB0aGUgVVMuCgpgYGB7cn0KcGxvdDEgPC0gZ2dwbG90KHNhbGFyaWVzX3JlY29kZSwgYWVzKHggPSB0b3RhbHllYXJseWNvbXBlbnNhdGlvbiwgY29sb3IgPSBzdGF0ZSkpICsgZ2VvbV9kZW5zaXR5KCkgKyAjIGRlbnNpdHkgcGxvdAp4bGltKDAsIDFlKzA2KSArCnhsYWIoIlRvdGFsIFllYXJseSBDb21wZW5zYXRpb24iKSsKICB5bGFiKCJEZW5zaXR5IikrCiAgZ2d0aXRsZSgiVGhlIFJlbGF0aW9uc2hpcCBCZXR3ZWVuIFRvdGFsIFllYXJseSBDb21wZW5zYXRpb24gYW5kIExvY2F0aW9uIikKcGxvdDEKYGBgCgojIyMgUXVlc3Rpb24gMjogSXMgdGhlcmUgYW4gYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgeWVhcnMgb2YgZXhwZXJpZW5jZSBhbmQgIHRvdGFsIGNvbXBlbnNhdGlvbiwgaW4gdGhlIHB1cnZpZXcgb2YgZ2VuZGVyPwoKTm93IHRoYXQgdGhlIGRpc2NyZXBhbmN5IGJldHdlZW4gdGhlIHJlZ2lvbnMgaGFzIGJlZW4gZXN0YWJsaXNoZWQsIHdlIHByb2NlZWRlZCB0byBoeXBvdGhlc2l6ZSB3aHkgdGhlIGRpc2NyZXBhbmNpZXMgZXhpc3QuIEFuZCBvbmUgb2YgdGhlIGZpcnN0IHZhcmlhYmxlcyB0aGF0IGRlZW1lZCB0byBiZSBwb3RlbnRpYWxseSByZXNwb25zaWJsZSB3YXMgdGhlIHRvdGFsIHllYXJzIG9mIGV4cGVyaWVuY2UuIFRvIGJlIHNwZWNpZmljLCB3ZSBoeXBvdGhlc2l6ZWQgdGhhdCBtYW55IHRoZSB2YXJ5aW5nIHJlZ2lvbnMgaGFkIHZhcnlpbmcgcm9sZXMgZnVsZmlsbGluZyB0aGVpciBuaWNoZXMgd2l0aGluIHRoZSBicm9hZGVyIElUIGluZHVzdHJ5LiBJbiB0aGF0LCBmb3IgZXhhbXBsZSwgdGhlIFdlc3QgcHJlZG9taW5hbnRseSB3YXMgdGhlICJnby10byIgZm9yIHNlbmlvci9zZWFzb25lZCBwZXJzb25uZWwsIHdoaWxlIHJlZ2lvbnMgc3VjaCBhcyB0aGUgU291dGggYW5kIE1pZHdlc3Qgd2VyZSB0aGUgZW50cnktbGV2ZWwgcmVnaW9ucyBmb3IgZnJlc2ggY29sbGVnZSBncmFkcyBvciBuZXdjb21lcnMgdG8gdGhlIGluZHVzdHJ5LiBJZiB0aGUgaHlwb3RoZXNpcyB3YXMgaW5kZWVkIHRydWUsIHRoZW4gdGhlIGRhdGEgdmlzdWFsaXphdGlvbiB3b3VsZCBuZWNlc3NhcmlseSBwb3J0cmF5IHRoYXQgdGhlIGhpZ2hlci1hdmVyYWdlIHNhbGFyeSByZWdpb25zIHdvdWxkIGJlIHByZWRvbWluYXRlbHkgaGF2ZSBhIG1vcmUgc2Vhc29uZWQgY29uc3RpdHVlbmN5LgoKSG93ZXZlciwgYmVmb3JlIHRoaXMgY291bGQgYmUgdGVzdGVkLCBvbmUga2V5IGFzc3VtcHRpb24gbmVlZGVkIHRvIGJlIHRlc3RlZDogdGhlIGFzc3VtcHRpb24gdGhhdCB3aGV0aGVyIHRvdGFsIHdvcmsgZXhwZXJpZW5jZSwgb24gYXZlcmFnZSwgdGVuZCB0byBpbmZsdWVuY2UgdG90YWwgeWVhcmx5IGNvbXBlbnNhdGlvbi4gQXMgc3VjaCBpbiBvcmRlciB0byB0ZXN0IHRoaXMga2V5IGFzc3VtcHRpb24sIHdlIGRlY2lkZWQgdG8gY3JlYXRlIGEgc2NhdHRlcnBsb3QgdG8gaWxsdXN0cmF0ZSB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiB0b3RhbCB5ZWFybHkgY29tcGVuc2F0aW9uIGFuZCB0b3RhbCB5ZWFycyBvZiBleHBlcmllbmNlLlRoZSB4LWF4aXMgaXMgdGhlIHRvdGFsIHllYXJzIG9mIGV4cGVyaWVuY2UsIHRoZSB5LWF4aXMgaXMgdGhlIHRvdGFsIHllYXJseSBjb21wZW5zYXRpb24sIGFuZCB0aGUgbGVnZW5kIGluY2x1ZGVzIGEgZGlmZmVyZW50aWF0aW9uIGJldHdlZW4gdGhlIGdlbmRlcnMgYnkgdGhlaXIgZGVub3RlZCByZXNwZWN0aXZlIGNvbG9ycy4gTmF0dXJhbGx5LCB0aGlzIG1lYW5zIHRoYXQgZXhjbHVzaW9uIG9mIG9ic2VydmF0aW9ucyB0aGF0IGRvIG5vdCBoYXZlIGRhdGEgb24gZ2VuZGVyIGFyZSBuZWNlc3NhcnkuCgpHZW5kZXIgd2FzIG9yaWdpbmFsbHkgYWRkZWQgdG8gdGhpcyB2aXN1YWxpemF0aW9uIHRvIHByb3ZpZGUgdGhlIHN0ZXBwaW5nIHN0b25lIGZvciBhbm90aGVyIHBvdGVudGlhbCBpbnF1aXJ5IGludG8gYSBkaWZmZXJlbnQgaHlwb3RoZXNpcyBzaW1pbGFyIHRvIHRoZSBvbmUgc3RhdGVkIGFib3ZlLiBBbiBhc3N1bXB0aW9uIHRvIGNoZWNrIGlmIGFueSBvZiB0aGUgcmVnaW9ucyBoYXZlIGEgc2tld2VkIHBvcHVsYXRpb24gaW4gdGVybXMgb2YgdGhlaXIgd29ya2ZvcmNlIHRoYXQgY291bGQgaW5mbHVlbmNlIHRoZSB0b3RhbCB5ZWFybHkgY29tcGVuc2F0aW9uIGluc29mYXIgYXMgdG8geWllbGQgYSBkaXNwYXJpdHkgYXMgc2VlbiBpbiBxdWVzdGlvbiAxLgoKVW5mb3J0dW5hdGVseSwgb3ZlcmFsbCwgdGhlIGtleSBhc3N1bXB0aW9uIHRoYXQgd2Ugc291Z2h0IHRvIHNjcnV0aW5pemUgZGlkIG5vdCB5aWVsZCBhbnkgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBjb3JyZWxhdGlvbnMuIEZ1cnRoZXJtb3JlLCBkdWUgdG8gdGhlIGNvbXBhcmF0aXZlbHkgZGVhcnRoIG9mIGZlbWFsZSBnZW5kZXIgZGF0YSB2YWx1ZXMsIGFueSBhc3N1bXB0aW9ucyByZWdhcmRpbmcgdGhlIHJvbGUgb2YgZ2VuZGVyIGhhcyBhbHNvIGJlZW4gcmVuZGVyZWQgaW5jb25jbHVzaXZlLgoKYGBge3J9CnNhbGFyaWVzXzIgPC0gc2FsYXJpZXMgJT4lCiAgZHJvcF9uYShnZW5kZXIpJT4lICNFeGNsdWRlIG9ic2VydmF0aW9ucyB3aXRob3V0IGEgZ2VuZGVyIGRhdGEKICBmaWx0ZXIoZ2VuZGVyID09ICJNYWxlInxnZW5kZXI9PSJGZW1hbGUiKSU+JQogIGZpbHRlcighaXMubmEodG90YWx5ZWFybHljb21wZW5zYXRpb24pKQogIApwbG90MiA8LXBsb3RfbHkoZGF0YSA9IHNhbGFyaWVzXzIsIAogICAgICAgIHggPSB+eWVhcnNvZmV4cGVyaWVuY2UsIAogICAgICAgIHk9IH50b3RhbHllYXJseWNvbXBlbnNhdGlvbiklPiUKICBhZGRfbWFya2Vycyhjb2xvciA9IH5nZW5kZXIpJT4lCiAgbGF5b3V0KHRpdGxlID0gIkFzc29jaWF0aW9uIEJldHdlZW4gWWVhcnMgb2YgU2VydmljZSBhbmQgVG90YWwgWWVhcmx5IENvbXBlbnNhdGlvbiIseGF4aXMgPSBsaXN0KHRpdGxlID0gJ1llYXJzIG9mIFNlcnZpY2UnKSwgCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdUb3RhbCBZZWFybHkgQ29tcGVuc2F0aW9uJykpCiAgCnBsb3QyCmBgYAoKIyMjIFF1ZXN0aW9uIDM6IElzIHRoZXJlIGFuIGFzc29jaWF0aW9uIGJldHdlZW4geWVhcnMgb2YgZXhwZXJpZW5jZSBhbmQgbG9jYXRpb24/CgpBbHRob3VnaCB0aGUga2V5IGFzc3VtcHRpb24gYXMgdG8gd2hldGhlciB0b3RhbCB5ZWFycyBvZiBleHBlcmllbmNlIGFuZCB0b3RhbCB5ZWFybHkgY29tcGVuc2F0aW9uIGhhZCBhbnkgaW1wYWN0ZnVsIGNvcnJlbGF0aW9uIHdhcyByZW5kZXJlZCBtb290IGluIHRoZSBxdWVzdGlvbiBhYm92ZSwgYW4gYWx0ZXJuYXRpdmUgZGlyZWN0aW9uIHdhcyBwcm9wb3NlZC4gQSBkaXJlY3Rpb24gaW4gd2hpY2ggdGhhdCByZXZlcnNlZCB0aGUgY29uZGl0aW9uYWwsICJjb3JyZWxhdGlvbmFsIiwgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHR3byB2YXJpYWJsZXMuIFdoYXQgaWYsIGluc3RlYWQgb2YgYXNzdW1pbmcgdGhhdCBncmVhdGVyIHRoZSBleHBlcmllbmNlLCB0aGUgZ3JlYXRlciB0aGUgY29tcGVuc2F0aW9uLCB0aGVyZSB3YXMgYW4gYWx0ZXJuYXRpdmUgY2F1c2UsIGEgY29uZm91bmRlciwgdGhhdCBpbmZsdWVuY2VzIHRoZSBzYWxhcnkgbGV2ZWxzPyBUaGlzIGNvdWxkIGJlIHNob3duIHRvIGhhdmUgc29tZSBkZWdyZWUgb2YgdHJ1dGggdG8gaXQsIGlmLCB0aGUgdmlzdWFsaXphdGlvbiBvZiB0aGUgdG90YWwgeWVhcnMgb2YgZXhwZXJpZW5jZSBhbmQgbG9jYXRpb24gcHJvdmlkZSBhIHBhcmFkb3hpY2FsIHJlbGF0aW9uc2hpcCB0byB0aGUgb25lIHBvcnRyYXllZCBpbiBxdWVzdGlvbiAxLgoKVGhlIGZvbGxvd2luZyB2aXN1YWxpemF0aW9uIHByb3ZlZCB0byBmaXQganVzdCB0aGF0LCB3aGVyZSB0aGUgV2VzdCBoYWQgdGhlIGxvd2VzdCB0b3RhbCBudW1iZXIgb2YgZW5naW5lZXJzIGluIHRvdGFsLCBhbmQgaW4gYWxtb3N0IGFsbCBiYW5kd2lkdGhzIG9mIGV4cGVyaWVuY2UgeWVhcnMuIFdoZXJlYXMsIGNvbXBhcmF0aXZlbHksIHRoZSBNaWR3ZXN0LCBOb3J0aGVhc3QsIGFuZCBTb3V0aCwgcmVzcGVjdGl2ZWx5LCBhbGwgaGFkIGhpZ2hlciBmcmVxdWVuY2llcyBpbiBtb3N0IGJhbmR3aWR0aHMganV4dGFwb3NlZCB0byB0aGUgV2VzdC4gQWx0aG91Z2ggdGhpcyB2aXN1YWxpemF0aW9uIGFsb25lIGRvZXMgbm90IHByb3ZpZGUgYW55IGRlZmluaXRpdmUgcHJvb2YgdGhhdCB0aGUgb3JpZ2luYWwgaHlwb3RoZXNpcyBvbiBleHBlcmllbmNlIGFuZCBjb21wZW5zYXRpb24gYmVpbmcgaW52YWxpZCwgaXQgZG9lcyBwcm92aWRlIGRlZmluaXRpdmUgcHJvb2YgdGhhdCB0aGVyZSBpcyBzb21lIGZvcm0gb2YgYSBjb25mb3VuZGVyIHRoYXQgaW5mbHVlbmNlcyB0aGUgcmVsYXRpb25zaGlwLiAKCmBgYHtyfQpwbG90MyA8LSBnZ3Bsb3Qoc2FsYXJpZXNfcmVjb2RlLCBhZXMoeCA9IHllYXJzb2ZleHBlcmllbmNlLCBjb2xvciA9IHN0YXRlKSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsKeGxhYigiWWVhcnMgT2YgRXhwZXJpZW5jZSIpKwogIHlsYWIoIkRlbnNpdHkiKSsKICBnZ3RpdGxlKCJUaGUgUmVsYXRpb25zaGlwIEJldHdlZW4gWWVhcnMgb2YgRXhwZXJpZW5jZSBhbmQgTG9jYXRpb24iKSMgZGVuc2l0eSBwbG90CgpwbG90MwpgYGAKCiMjIyBDb25jbHVzaW9uICYgSW1wbGljYXRpb25zCgpUbyBjb25jbHVkZSwgdGhyb3VnaCB0aGUgc2NydXRpbml6aW5nIHRocmVlIHByaW5jaXBhbCBxdWVzdGlvbnMgaW4gdGhlIGhvcGVzIG9mIGFuc3dlcmluZyB0aGUgc2FsYXJ5IGRpc2NyZXBhbmN5IGJldHdlZW4gdGhlIHZhcmlvdXMgcmVnaW9ucyBvZiB0aGUgVVMgaGFzIHByb3ZlZCBpbmNvbmNsdXNpdmUsIHRoZXJlIGlzIHN0cm9uZyBldmlkZW5jZSB0byBpbmRpY2F0ZSB0aGF0IHRoZXJlIGlzIGEgcG90ZW50aWFsIGNvbmZvdW5kZXIgdGhhdCBjb3VsZCBiZSBhdCBwbGF5LiBUcnV0aGZ1bGx5LCBvbmUgb2YgdGhlIGNvcmUgcXVlc3Rpb25zIHRoYXQgd2Ugb3JpZ2luYWxseSBhbnRpY2lwYXRlZCB0byBhbmFseXplIHdhcyB0aGUgZWR1Y2F0aW9uYWwgYXNwZWN0IG9mIHRoZSBkYXRhIHNldC4gSG93ZXZlciwgdXBvbiBkaXNjb3ZlcnksIHRvIG91ciBkaXNtYXksIHRoZSB2YXN0IG1ham9yaXR5IG9mIHRoZSBlZHVjYXRpb24gZGF0YSB2YWx1ZXMgd2VyZSBlbXB0eS4gV2UgYmVsaWV2ZWQgdGhhdCwgZnJvbSB0aGUgc3RhcnQsIHRoYXQgdGhlIGVkdWNhdGlvbmFsIGRpZmZlcmVuY2VzIGltcGFjdGluZyB0aGUgc2FsYXJpZXMgYW1vbmcgdGhlIHJlZ2lvbnMgdG8gYmUgdGhlIG1vc3QgY2hpZWZseSBwZXJ0aW5lbnQgcXVlc3Rpb24uIFVuZm9ydHVuYXRlbHksIGR1ZSB0byB0aGUgbGFjayBvZiBhdmFpbGFibGUgdXNhYmxlIGRhdGEsIHRoaXMgYXZlbnVlIG9mIGFwcHJvYWNoIHdhcyBkaXNiYXJyZWQuCgpNb3ZpbmcgZm9yd2FyZCwgaG93ZXZlciwgd2UgZW52aXNpb24gdGhhdCB3ZSB3aWxsIG1vZGlmeSB0aGUgaHlwb3RoZXNpcyBmb3JtdWxhdGlvbiBmb3JtYXQuIEFzIHRvIGFkZHJlc3MgdGhlIGNhdmVhdHMgc3Vycm91bmRpbmcgdGhlIHZhcmlhYmxlIGluIHF1ZXN0aW9uIHZpYSBleHRyYXBvbGF0aW5nIGRhdGEgd2l0aCBwb3RlbnRpYWwgb3V0c2lkZSBzb3VyY2UgaW50ZXJjaGFuZ2VzLiBVbHRpbWF0ZWx5LCB0aGlzIHdvdWxkIG1lYW4gdGhhdCB3ZSB3b3VsZCBzbG93bHkgYnVpbGQgb3VyIHdheSB1cCB0byByZWFjaCBhbiBhbmFseXNpcyB0aGF0IGVuY29tcGFzc2VzIHRoZSBjb3JlIHZhcmlhYmxlcyB0aGF0IHdlIGZvdW5kIHRvIGJlIHRoZSBtb3N0IHBlcnRpbmVudCB3aGlsZSBleGFtaW5pbmcgdGhpcyBkYXRhIHNldC4gU3Vic2VxdWVudGx5IGVuYWJsaW5nIHVzIHRvIGVtcGxveSBhIGFuIGFwcHJvYWNoIHZlY3RvciB0aGF0LCBob3BlZnVsbHksIHdpbGwgbm90IGJlIHN0b3BwZWQgZGVhZCBpbiBpdHMgdHJhY2tzIGR1ZSB0byB0aGUgbGFjayBvZiBzdWZmaWNpZW50IGRhdGEgdmFsdWVzLiBBbGwgaW4gYWxsLCB0aGlzIGV4ZXJjaXNlIHByb3ZpZGVkIGFuIG9wcG9ydHVuaXR5IHRvIGdhcm5lciB2YWx1YWJsZSBpbnNpZ2h0IGFuZCBjb21wcmVoZW5kIHRoZSBleGlnZW5jaWVzIG9mIHdoZW4gZGF0YSB2YWx1ZXMgYXJlIGxhY2tpbmcuCgoKIyMjIENvc3Qgb2YgTGl2aW5nIEV4cGxvcmF0aW9uCgpgYGB7cn0KY29sX2luZGV4ID0gcmVhZC5jc3YoZmlsZSA9ICcvVXNlcnMvYWx2aW5qaWFvL0Rlc2t0b3AvUVRNIDMwMlcvQ29zdF9vZl9saXZpbmdfaW5kZXguY3N2JykKYGBgCmBgYHtyfQpjb2xfaW5kZXgxIDwtIGNvbF9pbmRleCAlPiUKICBtdXRhdGUoCiAgICBDaXR5ID0gYXMuY2hhcmFjdGVyKENpdHkpLAogICAgQ2l0eV9OYW1lID0gc3RyX3NwbGl0KENpdHksICIsICIsIHNpbXBsaWZ5ID0gVFJVRSlbLCAxXSwKICAgIFN0YXRlID0gc3RyX3NwbGl0KENpdHksICIsICIsIHNpbXBsaWZ5ID0gVFJVRSlbLCAyXSwKICAgIENvdW50cnkgPSBzdHJfc3BsaXQoQ2l0eSwgIiwgIiwgc2ltcGxpZnkgPSBUUlVFKVssIDNdCiAgKSAlPiUKICBzZWxlY3QoLUNpdHkpCmBgYAoKYGBge3J9CnVzX2luZGV4IDwtIHN1YnNldChjb2xfaW5kZXgxLCBDb3VudHJ5ID09ICJVbml0ZWQgU3RhdGVzIikKIyBNYXBwaW5nIHN0YXRlIGluaXRpYWxzIHRvIHJlZ2lvbnMKcmVnaW9uX21hcHBpbmcgPC0gYygKICAiTlkiID0gIlRoZSBOb3J0aGVhc3QiLCAiQ0EiID0gIlRoZSBXZXN0IiwgIkhJIiA9ICJUaGUgV2VzdCIsICJBSyIgPSAiVGhlIFdlc3QiLCAiREMiID0gIlRoZSBTb3V0aCIsCiAgIlNDIiA9ICJUaGUgU291dGgiLCAiV0EiID0gIlRoZSBXZXN0IiwgIk5KIiA9ICJUaGUgTm9ydGhlYXN0IiwgIk1BIiA9ICJUaGUgTm9ydGhlYXN0IiwgIkNUIiA9ICJUaGUgTm9ydGhlYXN0IiwKICAiUEEiID0gIlRoZSBOb3J0aGVhc3QiLCAiSUwiID0gIlRoZSBNaWR3ZXN0IiwgIkNPIiA9ICJUaGUgV2VzdCIsICJWVCIgPSAiVGhlIE5vcnRoZWFzdCIsICJGTCIgPSAiVGhlIFNvdXRoIiwKICAiTUUiID0gIlRoZSBOb3J0aGVhc3QiLCAiT1IiID0gIlRoZSBXZXN0IiwgIk1EIiA9ICJUaGUgU291dGgiLCAiTEEiID0gIlRoZSBTb3V0aCIsICJOQyIgPSAiVGhlIFNvdXRoIiwgCiAgIk1OIiA9ICJUaGUgTWlkd2VzdCIsICJHQSIgPSAiVGhlIFNvdXRoIiwgIkFMIiA9ICJUaGUgU291dGgiLCAiSU4iID0gIlRoZSBNaWR3ZXN0IiwgIlRYIiA9ICJUaGUgU291dGgiLAogICJPSCIgPSAiVGhlIE1pZHdlc3QiLCAiTU8iID0gIlRoZSBNaWR3ZXN0IiwgIldJIiA9ICJUaGUgTWlkd2VzdCIsICJUTiIgPSAiVGhlIFNvdXRoIiwgIlZBIiA9ICJUaGUgU291dGgiLAogICJNSSIgPSAiVGhlIE1pZHdlc3QiLCAiTlYiID0gIlRoZSBXZXN0IiwgIkFSIiA9ICJUaGUgU291dGgiLCAiTk0iID0gIlRoZSBXZXN0IiwgIkFaIiA9ICJUaGUgV2VzdCIsICJLUyIgPSAiVGhlIE1pZHdlc3QiLAogICJVVCIgPSAiVGhlIFdlc3QiLCAiT0siID0gIlRoZSBTb3V0aCIsICJJQSIgPSAiVGhlIE1pZHdlc3QiLCAiS1kiID0gIlRoZSBTb3V0aCIsICJJRCIgPSAiVGhlIFdlc3QiCikKCnVzX2luZGV4X3IgPC0gdXNfaW5kZXggJT4lCiAgbXV0YXRlKAogICAgUmVnaW9ucyA9IGNhc2Vfd2hlbigKICAgICAgU3RhdGUgJWluJSBuYW1lcyhyZWdpb25fbWFwcGluZykgfiByZWdpb25fbWFwcGluZ1tTdGF0ZV0sCiAgICAgIFRSVUUgfiAiVW5rbm93biIgIAogICAgKQogICkKCmBgYAoKYGBge3J9CiMgUGxvdHRpbmcgdGhlIGRlbnNpdHkKZ2dwbG90KHVzX2luZGV4X3IsIGFlcyh4ID0gQ29zdC5vZi5MaXZpbmcuSW5kZXgsIGZpbGwgPSBSZWdpb25zKSkgKwogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoCiAgICAiVGhlIE5vcnRoZWFzdCIgPSAiYmx1ZSIsIAogICAgIlRoZSBXZXN0IiA9ICJncmVlbiIsIAogICAgIlRoZSBNaWR3ZXN0IiA9ICJvcmFuZ2UiLCAKICAgICJUaGUgU291dGgiID0gInJlZCIKICApKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiRGVuc2l0eSBQbG90IG9mIENvc3Qgb2YgTGl2aW5nIEluZGV4IGJ5IFJlZ2lvbnMiLAogICAgeCA9ICJDb3N0IG9mIExpdmluZyBJbmRleCIsCiAgICB5ID0gIkRlbnNpdHkiCiAgKQoKYGBgCiMjIyBTYWxhcnkgdnMuIE1ham9ycyB2cy4gR2VuZGVyIEV4cGxvcmF0aW9uCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgojIE9yZGVyIHRoZSBkYXRhc2V0IGJ5IE1pZC5DYXJlZXIuTWVkaWFuLlNhbGFyeQpXYWdlX3NvcnRlZCA8LSBXYWdlW29yZGVyKFdhZ2UkTWlkLkNhcmVlci5NZWRpYW4uU2FsYXJ5LCBkZWNyZWFzaW5nID0gVFJVRSksIF0KCiMgRXh0cmFjdCB0aGUgdG9wIHRlbiBhbmQgYm90dG9tIHRlbiByb3dzCnRvcF90ZW4gPC0gaGVhZChXYWdlX3NvcnRlZCwgMTApCmJvdHRvbV90ZW4gPC0gdGFpbChXYWdlX3NvcnRlZCwgMTApCgojIENyZWF0ZSBhIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIHRoZSBiYXIgcGxvdApwbG90X21ham9yX3NhbGFyeSA8LSBmdW5jdGlvbihkYXRhLCB0aXRsZSkgewogIGdncGxvdChkYXRhLCBhZXMoeCA9IHJlb3JkZXIoVW5kZXJncmFkdWF0ZS5NYWpvciwgTWlkLkNhcmVlci5NZWRpYW4uU2FsYXJ5KSwgeSA9IE1pZC5DYXJlZXIuTWVkaWFuLlNhbGFyeSkpICsKICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArCiAgICBjb29yZF9mbGlwKCkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gdGl0bGUsCiAgICAgIHggPSAiVW5kZXJncmFkdWF0ZSBNYWpvciIsCiAgICAgIHkgPSAiTWlkLUNhcmVlciBNZWRpYW4gU2FsYXJ5IgogICAgKQp9CgojIFBsb3QgdGhlIHRvcCB0ZW4gaGlnaGVzdApwbG90X3RvcF90ZW4gPC0gcGxvdF9tYWpvcl9zYWxhcnkodG9wX3RlbiwgIlRvcCBUZW4gSGlnaGVzdCBNaWQtQ2FyZWVyIE1lZGlhbiBTYWxhcmllcyIpCgojIFBsb3QgdGhlIGJvdHRvbSB0ZW4KcGxvdF9ib3R0b21fdGVuIDwtIHBsb3RfbWFqb3Jfc2FsYXJ5KGJvdHRvbV90ZW4sICJCb3R0b20gVGVuIE1pZC1DYXJlZXIgTWVkaWFuIFNhbGFyaWVzIikKCiMgRGlzcGxheSB0aGUgcGxvdHMgc2lkZSBieSBzaWRlCmxpYnJhcnkoZ3JpZEV4dHJhKQpncmlkLmFycmFuZ2UocGxvdF90b3BfdGVuLCBwbG90X2JvdHRvbV90ZW4sIG5jb2wgPSAyKQoKYGBgCgpgYGB7cn0KZ3JhZCA9IHJlYWQuY3N2KCdyZWNlbnQtZ3JhZHMuY3N2JykKZ3JhZF9zb3J0ZWQgPC0gZ3JhZFtvcmRlcihncmFkJFNoYXJlV29tZW4sIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQoKIyBFeHRyYWN0IHRoZSB0b3AgdGVuIGFuZCBib3R0b20gdGVuIHJvd3MKdG9wX3RlbiA8LSBoZWFkKGdyYWRfc29ydGVkLCAxMCkKYm90dG9tX3RlbiA8LSB0YWlsKGdyYWRfc29ydGVkLCAxMCkKCiMgQ3JlYXRlIGEgZnVuY3Rpb24gdG8gZ2VuZXJhdGUgdGhlIGJhciBwbG90CnBsb3RfbWFqb3Jfc2hhcmV3b21lbiA8LSBmdW5jdGlvbihkYXRhLCB0aXRsZSkgewogIGdncGxvdChkYXRhLCBhZXMoeCA9IHJlb3JkZXIoTWFqb3IsIFNoYXJlV29tZW4pLCB5ID0gU2hhcmVXb21lbiwgZmlsbCA9IGBNYWpvcl9jYXRlZ29yeWApKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgY29vcmRfZmxpcCgpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9IHRpdGxlLAogICAgICB4ID0gIk1ham9yIiwKICAgICAgeSA9ICJTaGFyZVdvbWVuIgogICAgKQp9CgojIFBsb3QgdGhlIHRvcCB0ZW4gaGlnaGVzdApwbG90X3RvcF90ZW4gPC0gcGxvdF9tYWpvcl9zaGFyZXdvbWVuKHRvcF90ZW4sICJUb3AgVGVuIEhpZ2hlc3QgU2hhcmVXb21lbiIpCgojIFBsb3QgdGhlIGJvdHRvbSB0ZW4KcGxvdF9ib3R0b21fdGVuIDwtIHBsb3RfbWFqb3Jfc2hhcmV3b21lbihib3R0b21fdGVuLCAiQm90dG9tIFRlbiBTaGFyZVdvbWVuIikKCiMgRGlzcGxheSB0aGUgcGxvdHMgc2lkZSBieSBzaWRlCmxpYnJhcnkoZ3JpZEV4dHJhKQpncmlkLmFycmFuZ2UocGxvdF90b3BfdGVuLCBwbG90X2JvdHRvbV90ZW4sIG5jb2wgPSAxKQpgYGAKCg==